<?php

namespace App\Services;

use App\Common\Libs\ArrayHelper;
use App\Common\Libs\Dispatch\Console;
use App\Common\Libs\HttpClient;
use App\Common\Libs\Json;
use App\Console\Commands\Controller\RepairArticleSrcCommand;
use App\Consts\GlobalArticleConst;
use App\Consts\GlobalConsoleConst;
use App\Consts\GlobalConst;
use App\Consts\GlobalUploadConst;
use App\Formats\ArticleFormat;
use App\Models\Field\UserField;
use App\Models\IndexArticle;
use App\Models\Select\ArticleSelect;
use App\Models\SysArticle;
use App\Models\SysArticleContent;
use App\Repository\BaseRepository;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class ArticleService extends BaseService
{
    private $_repository;

    private $_article;

    public function __construct()
    {
        parent::__construct();
        $this->_repository = repository()->ArticleRepository;
    }

    /**
     * 获取用户文章列表
     * @param $searchParams
     * @return array
     */
    public function getUserArticleList($searchParams)
    {
        $dataProvider = $this->_repository->userArticleList($searchParams);
        $pagination = $this->getPagination();
        $indexArticles = $dataProvider->get();

        $list = formats()->ArticleFormat->formatArticleList(ArrayHelper::getColumn($indexArticles, 'article_id'),
            $searchParams['current_user_id'], ArticleFormat::USER_ARTICLE_LIST);

        $list = ArrayHelper::multiSort($list, 'created_at', SORT_DESC);

        return self::outputMoreList($dataProvider, $pagination, $list);
    }

    /**
     * 获取搜索文章列表
     * @param $params
     * @return \Illuminate\Database\Eloquent\Builder|mixed
     */
    public function getSearchArticleList($params)
    {
        // get all id
        $idAry = $this->_repository->getArticleIdListBySearch($params);
        $query = IndexArticle::getInstance()
            ->whereIn('article_id', (array)ArrayHelper::toArray($idAry));
        // get id in page
        $lastId = $params['last_id'] ?? 0;
        $pagination = $this->getPagination();
        $count = $idAry->count();
        $idAry = $idAry->forPage($pagination->page + 1, $pagination->pageSize);
        $lastId = $idAry->last();
        $idAry = $idAry->toArray();
        if (empty($idAry)) return $this->searchList['count'];

        // get id in table
        $tabAry = $this->getTableIds($idAry, SysArticle::getBaseTableName());

        // get article list
        $articleAry = $this->_repository->getArticleListByTabIds($tabAry);
        $articleAry = $articleAry->keyBy('id')->toArray();
        $last = $articleAry[$lastId];
        unset($articleAry[$lastId]);
        $articleAry[$lastId] = $last;

        // get article extra info
        $list = $this->_repository->getArticleExtInfo($articleAry);

        // return result
        return self::outputMoreList((new BaseRepository())->setPagination($query), $pagination, $list);
    }

    /**
     * 获取相关文章列表
     * @param $searchParams
     * @return array|bool
     */
    public function getSimilarArticleList($searchParams)
    {
        $article = $this->_repository->getArticleByArticleId($searchParams['id']);
        if (!$article) {
            return false;
        }
        $dataProvider = $this->_repository->getUserOriginalArticleList(ArrayHelper::merge($searchParams, [
            'author_id' => $article->author_id,
        ]));
        $pagination = $this->getPagination(['page_size' => $searchParams['page_size']]);
        $indexArticles = $dataProvider->get();
        $articleIdArr = ArrayHelper::getColumn($indexArticles, 'article_id');
        if (count($articleIdArr) < $searchParams['page_size']) {
            $url = service()->ConfigService->getConfigByKey('articleSimilarUrl');
            $similarArticleResult = HttpClient::getInstance()->get($url, [
                'article_id' => $article->article_id,
                'user_id' => $article->author_id,
                'page_size' => $searchParams['page_size'] - count($articleIdArr)
            ]);
            if (!is_array($similarArticleResult) || !isset($similarArticleResult['data']['list'])) {
                return false;
            }
            $articleIdArr = ArrayHelper::merge($articleIdArr, ArrayHelper::getColumn($similarArticleResult['data']['list'], 'target_id'));
        }

        $list = formats()->ArticleFormat->formatArticleList($articleIdArr,
            $searchParams['current_user_id'], ArticleFormat::SIMILAR_ARTICLE_LIST);
        $list = ArrayHelper::multiSort($list, 'created_at', SORT_DESC);

        return self::outputMoreList($dataProvider, $pagination, $list);
    }

    /**
     * 通过文章ID获取文章
     * @param $articleId
     * @param string $selectScene
     * @return SysArticle|false|\Illuminate\Database\Eloquent\Builder|mixed|object
     */
    public function getArticleByArticleId($articleId, $selectScene = ArticleSelect::SELF_DETAIL)
    {
        if (empty($this->_article[$articleId])) {
            $article = $this->_repository->getArticleByArticleId($articleId, $selectScene);
            if (!$article) {
                return false;
            }
            $this->_article[$articleId] = $article;
        }

        return $this->_article[$articleId];
    }

    /**
     * 获取文章其他信息
     * @param SysArticle $article
     * @param string $currentUserId
     * @return array
     */
    public function getArticleMoreFields($article, $currentUserId)
    {
        $count = service()->CounterService->getArticleCount($article->article_id, $currentUserId, ['collect', 'note', 'recommend']);
        if (empty($count['recommend']) || $count['recommend'] == 0) {
            $count['recommend'] = rand(20, 50);
        }

        $noteList = service()->NoteService->getLineNotesByUserIdAndArticleId($currentUserId, $article->article_id);
        $noteList = $noteList->toArray();
        return [
            'content' => $this->_formatArticleContent($article->article_id),
            'is_collect' => service()->CollectService->judgeCollected($currentUserId, $article->article_id),
            'is_recommend' => service()->UserRecommendService->judgeUserIsRecommend($currentUserId, $article->article_id),
            'author' => $article->type == GlobalArticleConst::ARTICLE_TYPE_RECOMMEND ? (object)[] : ArrayHelper::merge($article->author->commonFormat(UserField::ARTICLE_LANDING), [
                'attention_status' => service()->RelationshipService->getAttentionStatus($currentUserId, $article->author->user_id)
            ]),
            'note_list' => array_map(static function ($noteList) {
                return [
                    'id' => $noteList['note_id'],
                    'start_index' => $noteList['start_index'],
                    'end_index' => $noteList['end_index'],
                ];
            }, $noteList) ?: [],
            'original' => service()->SpiderService->getArticleOriginalInfo($article),
            'recommend' => ArticleFormat::getArticleRecommendAvatar($article->article_id),
            'count' => $count
        ];
    }

    /**
     * 去【李世泉】格式化文章内容
     * @param $articleId
     * @return array|mixed
     */
    private function _formatArticleContent($articleId)
    {
        // 获取【李世泉】接口地址
        $url = service()->ConfigService->getConfigByKey('articleContentParserUrl') . $articleId . '?from=web';
        // 发送请求，文档见YAPI
        $content = HttpClient::getInstance()->get($url);
        if (is_array($content)) {
            Log::channel('script')->info('article_id' . $articleId . 'OSS文件没有---' . Json::encode($content));
            return SysArticleContent::getInstance($articleId)->where('article_id', $articleId)->value('content');
        }

        // 替换图片后的链接为：域名 + 正文图片资源路径 + jpg + ?x-oss-process=image/format,jpg
        $realUrl = env('ALIOSS_URL') . GlobalUploadConst::OBJECT_ARTICLE_EDITOR_PATH . Str::random(32) . '.jpg?x-oss-process=image/format,jpg';

        /**
         * 图片替换为队列替换，替换完成之前，可能会引起：
         *  1.笔记标位错误
         *  2.防盗链原因，图片不显示
         *
         * 因此进行替换成env('REDIRECT_ARTICLE')路径（由接口转发，解决2），且长度 = 替换完成后的长度（解决1）
         *
         * 为了使长度相等，需要动态计算临时参数$temp
         */
        $pattern = "/<img((?!src).)*src[\s]*=[\s]*[\'\"](?<src>[^\'\"]*)[\'\"]/i";
        preg_match_all($pattern, $content, $out, PREG_PATTERN_ORDER);
        $srcArr = $out['src'];
        foreach ($srcArr as $oldSrc) {
            if (strpos($oldSrc, 'data:image') === false && strpos($oldSrc, 'tingjun') === false) {
                $baseNewSrc = env('REDIRECT_ARTICLE') . md5($oldSrc) . "&aid={$articleId}&";
                $temp = Str::random(strlen($realUrl) - strlen($baseNewSrc));
                $content = str_replace($oldSrc, $baseNewSrc . $temp, $content);
            }
        }

        return $content;
    }

    /**
     * 通过ID验证文章是否可用
     * 可用：没有被删除，没有被屏蔽
     * @param $articleId
     * @return array|bool|SysArticle|null
     */
    public function verifyArticleIsAvailableByArticleId($articleId)
    {
        $article = $this->getArticleByArticleId($articleId);
        if (!$article) {
            return false;
        }
        if ($article->is_deleted == GlobalConst::IS_DELETED || $article->is_shield == GlobalConst::IS_SHIELD) {
            return false;
        }
        return $article;
    }

    /**
     * 异步替换文章封面图、正文中的图片
     * @param $articleInfo
     * @return bool
     */
    public function asyncRepairImage($articleInfo)
    {
        unset($articleInfo['content']);

        Console::getInstance(RepairArticleSrcCommand::class)
            ->push($articleInfo, GlobalConsoleConst::REPAIR_ARTICLE_SRC);

        return true;
    }
}
